﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SetupLauncher.Domain.Configuration;
using PSE.Deployment.TeamFoundation.Communication;
using PSE.Deployment.TeamFoundation.Entity;
using PSE.Deployment.TeamFoundation.Logic;
using System.Collections;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.Client;

namespace SetupLauncher.Domain.Logic
{
    public class TeamSystem
    {
        //TODO: Criar parametro de configuração para a URL do TFS
        TeamFoundationServer _tfs = new TeamFoundationServer("http://UTILCORP05:8080/");
        VersionControlServer _versionControl;
        
        Logger.ILoggable _log;
        
        public TeamSystem(Logger.ILoggable log)
        {
            _log = log;
            Initialize();
        }

        public TeamSystem()
        {
            Initialize();
        }

        private void Initialize()
        {
            _versionControl = (VersionControlServer)_tfs.GetService(typeof(VersionControlServer));
        }

        public void GetSetupSource(string productName, string teamSystemPath, string workSpacePath, string versionPath)
        {
            Exceptions.ValidationException exception = new Exceptions.ValidationException();

            if (string.IsNullOrEmpty(teamSystemPath))
                exception.AddValidation(new Exceptions.Validation
                {
                    Description = "Nenhum Caminho da pasta no TeamSystem foi Informado",
                    PropertyName = "teamSystemPath",
                    PropertyTitle = "Caminho da pasta no TeamSystem"
                });

            if (string.IsNullOrEmpty(productName))
                exception.AddValidation(new Exceptions.Validation
                {
                    Description = "Nenhum Nome de Produto foi Informado",
                    PropertyName = "systemName",
                    PropertyTitle = "Nome do Produto"
                });

            if (string.IsNullOrEmpty(workSpacePath))
                exception.AddValidation(new Exceptions.Validation
                {
                    Description = "Nenhum Caminho Pasta para Download do Código Fonte foi Informado",
                    PropertyName = "workSpacePath",
                    PropertyTitle = "Caminho Pasta para Download do Código Fonte"
                });

            if (string.IsNullOrEmpty(versionPath))
                exception.AddValidation(new Exceptions.Validation
                {
                    Description = "Nenhum Caminho da Versão Informado",
                    PropertyName = "version",
                    PropertyTitle = "Caminho da Versão"
                });

            if (exception.CountValidations > 0)
                throw exception;

            versionPath = versionPath + @"/x86";

            if (!ExistsTSFolder(versionPath))
            {
                exception.AddValidation(new Exceptions.Validation
                {
                    Description = string.Format("Caminho para pasta {0} no TeamSystem inexistente.", versionPath),
                    PropertyName = "SourceUri",
                    PropertyTitle = "Caminho Pasta no Team System"
                });

                throw exception;
            }

            DownloadFolder(versionPath, workSpacePath);
        }

        public void GetParametersSource(string parametersFile, string destination)
        {
            Exceptions.ValidationException exception = new Exceptions.ValidationException();

            if (string.IsNullOrEmpty(parametersFile))
                exception.AddValidation(new Exceptions.Validation
                {
                    Description = "Nenhum Caminho da pasta no TeamSystem foi Informado",
                    PropertyName = "parametersFolder",
                    PropertyTitle = "Caminho da pasta no TeamSystem"
                });

            if (string.IsNullOrEmpty(destination))
                exception.AddValidation(new Exceptions.Validation
                {
                    Description = "Nenhum Caminho de Destino foi Informado",
                    PropertyName = "destination",
                    PropertyTitle = "Caminho de Destino"
                });

            if (exception.CountValidations > 0)
                throw exception;

            if (!ExistsTSFile(parametersFile))
            {
                exception.AddValidation(new Exceptions.Validation
                {
                    Description = string.Format("Caminho para pasta {0} no TeamSystem inexistente.", parametersFile),
                    PropertyName = "SourceUri",
                    PropertyTitle = "Caminho Pasta no Team System"
                });

                throw exception;
            }

            DownloadFile(parametersFile, destination);
        }

        private void DownloadFolder(string teamSystemPath, string destination)
        {
            WorkspaceTasks tasks = null;
            try
            {
                WriteLog(string.Format("Iniciando o download da pasta {0} para {1}", teamSystemPath, destination));

                tasks = new WorkspaceTasks();

                tasks.TraceEvent += (sender, e) => WriteLog(e.Message);
                tasks.FileDownloadedEvent += (sender, e) =>
                    {
                        WriteLog(string.Format("Baixando: {0}", e.FileName));
                    };

                tasks.GetSource(teamSystemPath, destination);
            }
            catch (Exception ex)
            {
                WriteException(ex.Message);
                throw ex;
            }
            finally
            {
                if (tasks != null)
                    tasks.DeleteWorkspace();
            }
        }

        public void DownloadFile(string path, string destination)
        {
            WriteLog(string.Format("Baixando: {0}", path));
            var item = _versionControl.GetItem(path);
            _versionControl.DownloadFile(path, destination);
        }

        public Entity.Version GetLastUpdate(string path)
        {
            WriteLog("Conectando ao TeamSystem");

            try
            {
                WriteLog("Obtendo a última versão");
                int maxChangeSet = 0;
                int pos = -1;
                ItemSet items = _versionControl.GetItems(path, RecursionType.OneLevel);
                for (int i = 0; i <= (items.Items.Count() - 1); i++)
                {
                    if (items.Items[i].ItemType == ItemType.Folder)
                    {
                        if (items.Items[i].ChangesetId >= maxChangeSet)
                        {
                            maxChangeSet = items.Items[i].ChangesetId;
                            pos = i;
                        }
                    }
                }
                if (pos > 0)
                {
                    string url = items.Items[pos].ServerItem;
                    return new Entity.Version { Code = GetVersionCode(url), Path = url };
                }
                else
                    return null;
            }
            catch (Exception ex)
            {
                WriteException(ex.Message);
                throw ex;
            }
        }

        public IEnumerable<Entity.Version> ListFolders(string path)
        {
            ItemSet items = _versionControl.GetItems(path, RecursionType.OneLevel);
            for (int i = 0; i <= (items.Items.Count() - 1); i++)
            {
                if (items.Items[i].ItemType == ItemType.Folder)
                {
                    string url = items.Items[i].ServerItem;
                    Entity.Version folder = new Entity.Version { Code = GetVersionCode(url), Path = url };
                    WriteLog(string.Format("Obtendo a pasta {0}", folder.Path));
                    if(i != 0)
                        yield return folder;
                }
            }
        }

        private string GetVersionCode(string path)
        {
            string[] names = path.Split('/');
            if (names.Length > 0)
                return names[names.Length - 1];

            return path;
        }

        private bool ExistsTSFolder(string path)
        {
            return _versionControl.ServerItemExists(path, ItemType.Folder);
        }

        private bool ExistsTSFile(string path)
        {
            return _versionControl.ServerItemExists(path, ItemType.File);
        }

        private void WriteLog(string message)
        {
            if (_log == null)
                return;
            _log.Write(message);
        }

        private void WriteException(string message)
        {
            if (_log == null)
                return;
            _log.WriteException(message);
        }
    }
}
